#ifndef SUDOKUABSTRACTSOLVINGTECHNIQUE_H
#define SUDOKUABSTRACTSOLVINGTECHNIQUE_H

#include <QThread>
#include "SudokuData.h"

/**
  * Enum to specify type of solving technique
  */
enum TechniqueCategory
{
    TechniqueCategoryUnknown,
    FindValue,
    EliminateCandidate
};

class SudokuAbstractSolvingTechnique : public QThread
{
    Q_OBJECT

public:
    SudokuAbstractSolvingTechnique(QString name, CellFillerTypes type,
                                   TechniqueCategory category = TechniqueCategoryUnknown, QObject* parent = 0);


    virtual ~SudokuAbstractSolvingTechnique()
    {
        qDebug() << "~SudokuAbstractSolvingTechnique" << this;
    }

    inline QString getName() const { return mName; }
    inline CellFillerTypes getType() const { return mType; }
    inline TechniqueCategory getCategory() const { return mCategory; }
    inline int getCount() const { return mCount; }

    inline void setSudokuData(SudokuData* sudokuData) { mSudokuData = sudokuData; }

    //TODO remove
    virtual void run();
protected:

    virtual int solve() = 0;

    /**
      * From QThread
      */
    //virtual void run();

    // For pointing and claiming
    inline int getFirstTrueIndex(const QBitArray& bitArray) const
    {
        Q_ASSERT(bitArray.count(true) > 0);
        int firstPossibleInd = 0;
        while(!bitArray.testBit(firstPossibleInd))
            ++firstPossibleInd;
        return firstPossibleInd;
    }

protected:

    /**
      * Human readable technique name
      */
    QString mName;
    /**
      * Type of technique
      */
    CellFillerTypes mType;

    TechniqueCategory mCategory;

    /**
      * For methods of type FindValue this is count of found numbers,
      * for methods of type EliminateCandidate this is count of eliminated candidates
      */
    int mCount;

    /**
      * Doesn't own
      */
    SudokuData* mSudokuData;
};

#endif // SUDOKUABSTRACTSOLVINGTECHNIQUE_H
